package com.letoken.platform.admin.controller;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.letoken.platform.admin.service.AppUserWalletService;
import com.letoken.platform.pub.annotation.auth.NotAuthorization;
import com.letoken.platform.pub.enums.*;
import com.letoken.platform.pub.exception.ApiServiceException;
import com.letoken.platform.repo.app.dao.*;
import com.letoken.platform.repo.app.po.*;
import com.letoken.platform.repo.mall.po.AppBalanceHistory;
import com.letoken.platform.repo.mall.po.AppBalanceWallet;
import com.letoken.platform.repo.utlis.UniqueIDUtils;
import com.letoken.platform.repo.utlis.WebUtils;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

@Log4j2
@RestController
@RequestMapping("/manual")
public class ManualController {

    @Resource
    private AppFundInfoMapper appFundInfoMapper;

    @Resource
    private AppFundV2InfoMapper appFundV2InfoMapper;

    @Resource
    private AppFundV2DetailMapper appFundV2DetailMapper;

    @Resource
    private AppUserWalletService appUserWalletService;

    @Resource
    private AppUserWalletMapper appUserWalletMapper;

    @Resource
    private DataSourceTransactionManager dataSourceTransactionManager;

    @Resource
    private TransactionDefinition transactionDefinition;

    @Resource
    private AppUserAssetsHistoryMapper appUserAssetsHistoryMapper;

    @Resource
    private AppBalanceWalletMapper appBalanceWalletMapper;

    @Resource
    private AppBalanceHistoryMapper appBalanceHistoryMapper;

    @Resource
    private AppMiningInfoMapper appMiningInfoMapper;

    @Resource
    private AppMiningDetailMapper appMiningDetailMapper;

    @NotAuthorization
    @PostMapping("/fund/redemption")
    public void releaseFund(@RequestBody HashMap<String, String> reqBody) {
        log.info("start release fund");

        String sign;
        if (CollectionUtils.isEmpty(reqBody) || (!StringUtils.hasLength(sign = reqBody.get("sign")))) {
            return;
        }

        if (!sign.equals("AladdinFundRedemption")) {
            return;
        }

        QueryWrapper<AppFundInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("type", 1);
        String id = reqBody.get("id");
        if (StringUtils.hasLength(id)) {
            queryWrapper.eq("id", Integer.valueOf(id));
        }

        String userId = reqBody.get("userId");
        if (StringUtils.hasLength(userId)) {
            queryWrapper.eq("user_id", Integer.valueOf(userId));
        }

        String userIds = reqBody.get("userIds");
        if (StringUtils.hasLength(userIds)) {
            queryWrapper.in("user_id", Arrays.stream(userIds.split(",")).map(Integer::valueOf).collect(Collectors.toList()));
        }

        List<AppFundInfo> funds = appFundInfoMapper.selectList(queryWrapper);

        for (AppFundInfo fund : funds) {
            TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);
            try {
                AppFundInfo updateFund = new AppFundInfo();
                updateFund.setExpirationTime(LocalDateTime.of(2024, 2, 22, 23, 59, 59));
                updateFund.setType(2);
                updateFund.setId(fund.getId());
                appFundInfoMapper.updateById(updateFund);
                if (fund.getState() == 1) {
                    AppUserWallet userWallet = appUserWalletMapper.selectForUpdate2(fund.getUserId(), 2);

                    AppUserWallet userWalletUpdate = new AppUserWallet();
                    userWalletUpdate.setAvailableBalance(userWallet.getAvailableBalance().add(fund.getFund()));
                    userWalletUpdate.setId(userWallet.getId());
                    userWalletUpdate.updateById();

                    AppUserAssetsHistory fundRedemptionAssetHistory = new AppUserAssetsHistory();
                    fundRedemptionAssetHistory.setUserId(fund.getUserId());
                    fundRedemptionAssetHistory.setType(TokenTransactionTypeEnum.FUND_SELL.getValue());
                    fundRedemptionAssetHistory.setStatus(TokenTransactionStatusEnum.COMPLETED.getValue());
                    fundRedemptionAssetHistory.setTokenId(LetokenTokenTypeEnum.LET.getId());
                    fundRedemptionAssetHistory.setAmount(fund.getFund());
                    fundRedemptionAssetHistory.setBalance(userWallet.getAvailableBalance().add(fund.getFund()));
                    fundRedemptionAssetHistory.setCreateTime(LocalDateTime.now());
                    fundRedemptionAssetHistory.setUpdateTime(LocalDateTime.now());
                    appUserAssetsHistoryMapper.insert(fundRedemptionAssetHistory);
                }
                dataSourceTransactionManager.commit(transactionStatus);
                log.info("redemption fund id:{}", fund.getId());
            } catch (Exception e) {
                log.error("error to redemption fund error id:" + fund.getId(), e);
                dataSourceTransactionManager.rollback(transactionStatus);
            }
        }
        log.info("finish release fund");
    }


    @NotAuthorization
    @PostMapping("/fund/issue")
    public void fundIssue(@RequestBody HashMap<String, String> reqBody) {

        log.info("start issue fund");
        String sign;
        if (CollectionUtils.isEmpty(reqBody) || (!StringUtils.hasLength(sign = reqBody.get("sign")))) {
            return;
        }
        if (!sign.equals("AladdinFundIssue")) {
            return;
        }

        QueryWrapper<AppUserWallet> walletQueryWrapper = new QueryWrapper<>();
        walletQueryWrapper.eq("token_id", 2);
        walletQueryWrapper.eq("available_balance", 100);

        String userId = reqBody.get("userId");
        if (StringUtils.hasLength(userId)) {
            walletQueryWrapper.eq("user_id", Integer.valueOf(userId));
        }

        List<AppUserWallet> appUserWallets = appUserWalletMapper.selectList(walletQueryWrapper);

        for (AppUserWallet appUserWallet : appUserWallets) {
            TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);
            try {
                AppUserWallet wallet = appUserWalletMapper.selectForUpdate(appUserWallet.getId());

                AppFundV2Info appFundV2Info = appFundV2InfoMapper.selectBYUserId(appUserWallet.getUserId());

                BigDecimal fund = wallet.getAvailableBalance().multiply(new BigDecimal("2"));

                AppFundV2Detail appFundV2Detail = new AppFundV2Detail();
                appFundV2Detail.setAmount(fund);
                appFundV2Detail.setUserId(wallet.getUserId());
                appFundV2Detail.setCreateTime(LocalDateTime.now());
                appFundV2Detail.setType(1);

                if (null == appFundV2Info) {
                    appFundV2Info = new AppFundV2Info();
                    appFundV2Info.setUserId(wallet.getUserId());
                    appFundV2Info.setRetained(fund);
                    appFundV2Info.setCreateTime(LocalDateTime.now());
                    appFundV2Info.setFund(wallet.getAvailableBalance());
                    appFundV2Info.insert();
                    appFundV2Detail.setAfterAmount(fund);
                } else {
                    AppFundV2Info appFundV2InfoUpdate = new AppFundV2Info();
                    UpdateWrapper<AppFundV2Info> updateWrapper = new UpdateWrapper<>();
                    updateWrapper.set("fund", appFundV2Info.getFund().add(wallet.getAvailableBalance()));
                    updateWrapper.set("retained", appFundV2Info.getRetained().add(fund));
                    updateWrapper.set("update_time", LocalDateTime.now());
                    updateWrapper.eq("user_id", wallet.getUserId());
                    appFundV2InfoUpdate.update(updateWrapper);
                    appFundV2Detail.setAfterAmount(appFundV2Info.getFund().add(fund));
                }

                appFundV2Detail.insert();

                AppUserAssetsHistory issuanceFundAssetHistory = new AppUserAssetsHistory();
                issuanceFundAssetHistory.setUserId(wallet.getUserId());
                issuanceFundAssetHistory.setType(TokenTransactionTypeEnum.FUND_ISSUE.getValue());
                issuanceFundAssetHistory.setStatus(TokenTransactionStatusEnum.COMPLETED.getValue());
                issuanceFundAssetHistory.setTokenId(LetokenTokenTypeEnum.LET.getId());
                issuanceFundAssetHistory.setAmount(wallet.getAvailableBalance().negate());
                issuanceFundAssetHistory.setBalance(BigDecimal.ZERO);
                issuanceFundAssetHistory.setCreateTime(LocalDateTime.now());
                issuanceFundAssetHistory.setUpdateTime(LocalDateTime.now());
                appUserAssetsHistoryMapper.insert(issuanceFundAssetHistory);

                AppUserWallet userWalletUpdate = new AppUserWallet();
                userWalletUpdate.setAvailableBalance(BigDecimal.ZERO);
                userWalletUpdate.setId(wallet.getId());
                userWalletUpdate.updateById();

                dataSourceTransactionManager.commit(transactionStatus);
            } catch (Exception e) {
                log.error("usdt2let error userId:" + appUserWallet.getUserId(), e);
                dataSourceTransactionManager.rollback(transactionStatus);
            }
        }
        log.info("end issue fund");
    }


    @NotAuthorization
    @PostMapping("/usdt2let")
    public void usdt2let(@RequestBody HashMap<String, String> reqBody) {

        log.info("start usdt2let");
        String sign;
        if (CollectionUtils.isEmpty(reqBody) || (!StringUtils.hasLength(sign = reqBody.get("sign")))) {
            return;
        }
        if (!sign.equals("AladdinUsdt2let")) {
            return;
        }
        QueryWrapper<AppUserWallet> walletQueryWrapper = new QueryWrapper<>();
        walletQueryWrapper.eq("token_id", 1);
        walletQueryWrapper.gt("available_balance", 0);

        String userId = reqBody.get("userId");
        if (StringUtils.hasLength(userId)) {
            walletQueryWrapper.eq("user_id", Integer.valueOf(userId));
        }

        List<AppUserWallet> appUserWallets = appUserWalletMapper.selectList(walletQueryWrapper);

        for (AppUserWallet appUserWallet : appUserWallets) {
            TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);
            try {
                AppUserWallet usdtWallet = appUserWalletMapper.selectForUpdate(appUserWallet.getId());
                AppUserWallet letWallet = appUserWalletMapper.selectForUpdate2(usdtWallet.getUserId(), 2);

                if (null == letWallet) {
                    log.error("user not have let wallet uid:{}", appUserWallet.getUserId());
                } else {
                    AppUserWallet usdtWalletUpdate = new AppUserWallet();
                    usdtWalletUpdate.setId(usdtWallet.getId());
                    usdtWalletUpdate.setAvailableBalance(BigDecimal.ZERO);

                    AppUserWallet letWalletUpdate = new AppUserWallet();
                    letWalletUpdate.setId(letWallet.getId());
                    letWalletUpdate.setAvailableBalance(letWallet.getAvailableBalance().add(usdtWallet.getAvailableBalance()));

                    AppUserAssetsHistory usdtAssetHistory = new AppUserAssetsHistory();
                    usdtAssetHistory.setUserId(appUserWallet.getUserId());
                    usdtAssetHistory.setType(TokenTransactionTypeEnum.USDT2LET.getValue());
                    usdtAssetHistory.setStatus(TokenTransactionStatusEnum.COMPLETED.getValue());
                    usdtAssetHistory.setTokenId(LetokenTokenTypeEnum.USDT.getId());
                    usdtAssetHistory.setAmount(usdtWallet.getAvailableBalance().negate());
                    usdtAssetHistory.setBalance(usdtWalletUpdate.getAvailableBalance());
                    usdtAssetHistory.setCreateTime(LocalDateTime.now());
                    usdtAssetHistory.setUpdateTime(LocalDateTime.now());
                    appUserAssetsHistoryMapper.insert(usdtAssetHistory);

                    AppUserAssetsHistory letAssetHistory = new AppUserAssetsHistory();
                    letAssetHistory.setUserId(appUserWallet.getUserId());
                    letAssetHistory.setType(TokenTransactionTypeEnum.USDT2LET.getValue());
                    letAssetHistory.setStatus(TokenTransactionStatusEnum.COMPLETED.getValue());
                    letAssetHistory.setTokenId(LetokenTokenTypeEnum.LET.getId());
                    letAssetHistory.setAmount(usdtWallet.getAvailableBalance());
                    letAssetHistory.setBalance(letWalletUpdate.getAvailableBalance());
                    letAssetHistory.setCreateTime(LocalDateTime.now());
                    letAssetHistory.setUpdateTime(LocalDateTime.now());
                    appUserAssetsHistoryMapper.insert(letAssetHistory);

                    usdtWalletUpdate.updateById();

                    letWalletUpdate.updateById();
                }
                dataSourceTransactionManager.commit(transactionStatus);
            } catch (Exception e) {
                log.error("usdt2let error userId:" + appUserWallet.getUserId(), e);
                dataSourceTransactionManager.rollback(transactionStatus);
            }

        }

        log.info("end usdt2let");

    }


    @NotAuthorization
    @PostMapping("/yuebao2let")
    public void yuebao2let(@RequestBody HashMap<String, String> reqBody) {

        log.info("start yuebao 2 let");
        String sign;
        if (CollectionUtils.isEmpty(reqBody) || (!StringUtils.hasLength(sign = reqBody.get("sign")))) {
            return;
        }
        if (!sign.equals("AladdinYuebao2let")) {
            return;
        }

        QueryWrapper<AppBalanceWallet> walletQueryWrapper = new QueryWrapper<>();
        walletQueryWrapper.eq("token_id", 2);
        walletQueryWrapper.gt("balance", 0);

        List<AppBalanceWallet> balanceWallets = appBalanceWalletMapper.selectList(walletQueryWrapper);

        for (AppBalanceWallet balanceWallet : balanceWallets) {
            TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);
            try {
                AppBalanceWallet yuebaoWallet = appBalanceWalletMapper.selectForUpdate(balanceWallet.getId());
                AppUserWallet letWallet = appUserWalletMapper.selectForUpdate2(yuebaoWallet.getUserId(), 2);

                if (null == letWallet) {
                    log.error("user not have let wallet uid:{}", yuebaoWallet.getUserId());
                } else {
                    AppBalanceWallet yuebaoWalletUpdate = new AppBalanceWallet();
                    yuebaoWalletUpdate.setId(yuebaoWallet.getId());
                    yuebaoWalletUpdate.setBalance(BigDecimal.ZERO);

                    AppUserWallet letWalletUpdate = new AppUserWallet();
                    letWalletUpdate.setId(letWallet.getId());
                    letWalletUpdate.setAvailableBalance(letWallet.getAvailableBalance().add(yuebaoWallet.getBalance()));


                    AppBalanceHistory appBalanceHistory = new AppBalanceHistory();
                    appBalanceHistory.setBalance(BigDecimal.ZERO);
                    appBalanceHistory.setAmount(yuebaoWallet.getBalance().negate());
                    appBalanceHistory.setType(BalanceTypeEnum.TRANSFER_OUT.ordinal());
                    appBalanceHistory.setInOut(InOutTypeEnum.OUT.ordinal());
                    appBalanceHistory.setSeqNo(UniqueIDUtils.genSeqNo("IC"));
                    appBalanceHistory.setTokenId(LetokenTokenTypeEnum.LET.getId());
                    appBalanceHistory.setUserId(yuebaoWallet.getUserId());
                    appBalanceHistory.setCreateTime(LocalDateTime.now());
                    appBalanceHistoryMapper.insert(appBalanceHistory);

                    AppUserAssetsHistory yuebaoAssetHistory = new AppUserAssetsHistory();
                    yuebaoAssetHistory.setUserId(yuebaoWallet.getUserId());
                    yuebaoAssetHistory.setType(TokenTransactionTypeEnum.TRANSFER_IN_BALANCE.getValue());
                    yuebaoAssetHistory.setStatus(TokenTransactionStatusEnum.COMPLETED.getValue());
                    yuebaoAssetHistory.setTokenId(LetokenTokenTypeEnum.LET.getId());
                    yuebaoAssetHistory.setAmount(yuebaoWallet.getBalance());
                    yuebaoAssetHistory.setBalance(letWalletUpdate.getAvailableBalance());
                    yuebaoAssetHistory.setCreateTime(LocalDateTime.now());
                    yuebaoAssetHistory.setUpdateTime(LocalDateTime.now());
                    appUserAssetsHistoryMapper.insert(yuebaoAssetHistory);

                    yuebaoWalletUpdate.updateById();

                    letWalletUpdate.updateById();
                }
                dataSourceTransactionManager.commit(transactionStatus);
            } catch (Exception e) {
                log.error("yuebao2let error userId:" + balanceWallet.getUserId(), e);
                dataSourceTransactionManager.rollback(transactionStatus);
            }
        }
        log.info("end yuebao 2 let");


    }


    @NotAuthorization
    @PostMapping("/cap")
    public void reissue() {
        log.info("start cap");

        QueryWrapper<AppFundV2Detail> queryWrapper = new QueryWrapper<>();
        queryWrapper.gt("create_time", "2024-02-24 18:00:00");
        queryWrapper.lt("create_time", "2024-02-24 23:59:59");
        List<AppFundV2Detail> appFundV2Details = appFundV2DetailMapper.selectList(queryWrapper);

        QueryWrapper<AppMiningDetail> appMiningDetailQueryWrapper = new QueryWrapper<>();
        queryWrapper.ge("create_time", "2024-02-26 18:55:44");
        queryWrapper.le("create_time", "2024-02-26 18:56:55");
        List<AppMiningDetail> appMiningDetails = appMiningDetailMapper.selectList(appMiningDetailQueryWrapper);

        Set<Integer> userIds = appMiningDetails.stream().map(AppMiningDetail::getUserId).collect(Collectors.toSet());

        for (AppFundV2Detail appFundV2Detail : appFundV2Details) {
            if(userIds.contains(appFundV2Detail.getUserId())){
                continue;
            }

            TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);
            try {
                AppMiningInfo appMiningInfo = appMiningInfoMapper.selectOne(new QueryWrapper<AppMiningInfo>().eq("user_id", appFundV2Detail.getUserId()));

                BigDecimal amount = appFundV2Detail.getAmount().divide(new BigDecimal("2"),8, RoundingMode.HALF_UP).multiply(new BigDecimal("0.1"));
                if (ObjectUtils.isEmpty(appMiningInfo)) {
                    appMiningInfo = new AppMiningInfo();
                    appMiningInfo.setCreateTime(LocalDateTime.now());
                    appMiningInfo.setAmount(amount);
                    appMiningInfo.setAccumulateIncome(BigDecimal.ZERO);
                    appMiningInfo.setUserId(appFundV2Detail.getUserId());
                    appMiningInfo.insert();
                } else {
                    appMiningInfo = appMiningInfoMapper.selectForUpdate(appMiningInfo.getId());
                    AppMiningInfo appMiningInfoUpdate = new AppMiningInfo();
                    appMiningInfoUpdate.setId(appMiningInfo.getId());
                    appMiningInfoUpdate.setAmount(appMiningInfo.getAmount().add(amount));
                    appMiningInfoUpdate.updateById();
                }

                AppMiningDetail appMiningDetail = new AppMiningDetail();
                appMiningDetail.setType(1);
                appMiningDetail.setAmount(amount);
                appMiningDetail.setUserId(appFundV2Detail.getUserId());
                appMiningDetail.setCreateTime(LocalDateTime.now());
                appMiningDetail.insert();

//                AppUserAssetsHistory assetHistory = new AppUserAssetsHistory();
//                assetHistory.setUserId(userId);
//                assetHistory.setType(TokenTransactionTypeEnum.PLEDGE.getValue());
//                assetHistory.setStatus(TokenTransactionStatusEnum.COMPLETED.getValue());
//                assetHistory.setTokenId(LetokenTokenTypeEnum.CAPA.getId());
//                assetHistory.setAmount(amount.negate());
//                assetHistory.setSn(appMiningDetail.getId().toString());
//                assetHistory.setBalance(updateW.getAvailableBalance());
//                assetHistory.setCreateTime(LocalDateTime.now());
//                assetHistory.setUpdateTime(assetHistory.getCreateTime());
//                assetHistory.insert();
                dataSourceTransactionManager.commit(transactionStatus);
            } catch (Exception e) {
                log.error("yuebao2let error userId:" + appFundV2Detail.getUserId(), e);
                dataSourceTransactionManager.rollback(transactionStatus);
            }
        }
        log.info("end cap");
    }
}
